using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Graphics;
using System.Windows.Forms;
using Graphics.Geometries;
using ImagesMath;
using ImagesMath.Transformations;
using ImagesMath.Repere;
using Graphics.Films;


namespace XMLConverter
{
    public class XMLGeometryConverter
    {
        public XMLGeometryConverter()
        {

        }

        public List<Graphics.Object3D> ParseGeometries(string path)
        {
            List<Graphics.Object3D> geometries = new List<Graphics.Object3D>();
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(path);
                foreach (XmlNode node in doc.ChildNodes)
                {
                    Application.DoEvents();
                    foreach (XmlNode n in node.ChildNodes)
                    {
                        Graphics.Object3D geo = ReadGeometriesNode(n);
                        if (geo != null)
                        {
                            geometries.Add(geo);
                        }
                    }
                }
            }
            catch (XmlException exception)
            {
                 MessageBox.Show(exception.ToString());
            }
            return geometries;
            
        }

        public List<Graphics.Light> ParseLights(string path)
        {
            List<Graphics.Light> lights = new List<Light>();
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(path);
                foreach (XmlNode node in doc.ChildNodes)
                {
                    Application.DoEvents();
                    foreach (XmlNode n in node.ChildNodes)
                    {


                        Graphics.Light light = ReadLightNode(n);
                        if (light != null)
                        {
                            lights.Add(light);
                        }
                    }
                }
            }
            catch (XmlException exception)
            {
                MessageBox.Show(exception.ToString());
            }
            return lights;

        }

        public Camera ParseCamera(string path)
        {
           
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(path);
                foreach (XmlNode node in doc.ChildNodes)
                {
                    Application.DoEvents();
                    foreach (XmlNode n in node.ChildNodes)
                    {


                        Camera camera = ReadCameraNode(n);
                        if (camera != null)
                        {
                            return camera;
                        }
                    }
                }
            }
            catch (XmlException exception)
            {
                MessageBox.Show(exception.ToString());
            }
            return null;

        }

        public Film ParseFilm(string path)
        {

            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(path);
                foreach (XmlNode node in doc.ChildNodes)
                {
                    Application.DoEvents();
                    foreach (XmlNode n in node.ChildNodes)
                    {


                        Film film = ReadFilmNode(n);
                        if (film != null)
                        {
                            return film;
                        }
                    }
                }
            }
            catch (XmlException exception)
            {
                MessageBox.Show(exception.ToString());
            }
            return null;

        }

        public Graphics.Object3D ReadGeometriesNode(XmlNode node)
        {
            Graphics.Form geo = null;
            Transformation transformation = null;
            Material material = null;
            BaseShader shader = new BaseShader();
            Mesh mesh = new Mesh();
            foreach (XmlAttribute a in node.Attributes)
            {
                if (node.Name == "Form")
                {
                    if (a.Name == "type")
                    {
                        if (a.Value == "sphere")
                        {
                            geo = new Sphere();
                        }
                        if (a.Value == "cube")
                        {
                            geo = new Cube();
                        }
                        if (a.Value == "cylindre")
                        {
                            geo = new Cylinder();
                        }
                        if (a.Value == "plan")
                        {
                            geo = new Plane();
                        }
                        if (a.Value == "cone")
                        {
                            geo = new Cone();
                        }
                        if (a.Value == "mesh")
                        {
                            geo = new Graphics.Form();
                        }
                        //else
                        //{
                        //    geo = new Graphics.Form();
                        //}
                    }
                    else if (a.Name == "name")
                    {
                        geo.setName(a.Value);
                    }
                }
            }

            if (node.Name == "Form")
            {
                //read geometry's children
                foreach (XmlNode n in node.ChildNodes)
                {
                    if (n.Name == "Transformation")
                    {
                        transformation = new Transformation();
                        foreach (XmlNode tn in n.ChildNodes)
                        {
                            double x = 0, y = 0, z = 0, a = 0;
                            foreach (XmlAttribute at in tn.Attributes)
                            {
                                switch (at.Name)
                                {
                                    case "x":
                                        x = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "y":
                                        y = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "z":
                                        z = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "a":
                                        a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                }
                            }
                            if (tn.Name == "Scaling")
                            {
                                transformation = transformation.rightMultiply(new Scaling(x, y, z));
                            }
                            else if (tn.Name == "Translation")
                            {
                                transformation = transformation.rightMultiply(new Translation(new VR3(x, y, z)));
                            }
                            else if (tn.Name == "Rotation")
                            {
                                transformation = transformation.rightMultiply(new Rotation(new VR3(x, y, z), a));
                            }
                            else if (tn.Name == "RotationX")
                            {
                                //double theta = -Math.PI / 2;

                                //double a = Math.Cos(theta);
                                ////a = -ImageMath.EPS;
                                //double b = Math.Sin(theta);
                                //double c = -(Math.Sin(theta));
                                //double d = Math.Cos(theta);
                                //d = a;
                                //M33 m = new M33(1.0, 0.0, 0.0,0.0 ,a,b , 0, c, d, true);
                                M33 m = new M33(new VR3(1, 0, 0), new VR3(0, -2.0510342851533115e-010, -1), new VR3(0, 1, -2.0510342851533115e-010), true);
                                //RotationX rotx = new RotationX(-Math.PI/2);
                                //transformation = new Transformation(rotx.lba);
                                transformation = new Transformation(m);

                            }
                        }
                    }
                    if (n.Name == "Material")
                    {
                        material = new Material();
                        foreach (XmlNode m in n.ChildNodes)
                        {
                            float r = 0.0f, g = 0.0f, b = 0.0f, k = 0.0f, f = 0.0f, i = 0.0f, e = 0.0f;
                            string path = "";
                            foreach (XmlAttribute at in m.Attributes)
                            {
                                switch (at.Name)
                                {
                                    case "r":

                                        r = float.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "g":
                                        g = float.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "b":
                                        b = float.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "k":
                                        k = float.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "f":
                                        f = float.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "i":
                                        i = float.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "e":
                                        e = float.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                        break;
                                    case "path":
                                        path = at.Value;
                                        break;

                                }
                            }
                            if (m.Name == "Ambiant")
                            {
                                material.SetAmbient(k, new TNI.Color(r, g, b));
                            }
                            else if (m.Name == "Diffuse")
                            {
                                material.SetDiffuse(k, new TNI.Color(r, g, b));
                            }
                            else if (m.Name == "Specular")
                            {
                                material.SetSpecular(k, e, new TNI.Color(r, g, b));
                            }
                            else if (m.Name == "Reflection")
                            {
                                material.SetReflection(k);
                            }
                            else if (m.Name == "Transmission")
                            {
                                material.SetTransmission(k, i);
                            }
                            else if (m.Name == "Texture")
                            {
                                material.SetTexture(new Texture(path));
                            }
                        }
                    }
                    else if (n.Name == "Shader")
                    {
                        string path = "";
                        foreach (XmlAttribute at in n.Attributes)
                        {
                            switch (at.Name)
                            {
                                case "path":

                                    path = at.Value;
                                    break;
                            }
                        }
                        shader.Path = path;
                    }
                    else if (n.Name == "Mesh")
                    {
                        string path = "";
                        foreach (XmlAttribute at in n.Attributes)
                        {
                            switch (at.Name)
                            {
                                case "path":

                                    path = at.Value;
                                    break;
                            }
                        }
                        mesh.Path = path;
                    }
                }

                Graphics.Object3D obj = new Graphics.Object3D(geo, material, transformation);
                obj.Mesh = mesh;
                obj.BaseShader = shader;
                return obj;
            }
            return null;
        }

        public Graphics.Light ReadLightNode(XmlNode node)
        {
            Graphics.Light light = null;
            PR3 direction = null;
            PR3 distance = null;
            double angle = 0;
            
            foreach (XmlNode n in node.ChildNodes)
            {
                if (n.Name == "Direction")
                {

                    double x = 0, y = 0, z = 0, a = 0;
                    foreach (XmlAttribute at in n.Attributes)
                    {
                        switch (at.Name)
                        {
                            case "x":
                                x = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "y":
                                y = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "z":
                                z = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "a":
                                a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                        }
                    }
                    direction = new PR3(x, y, z);
                }
                if (n.Name == "Position")
                {

                    double x = 0, y = 0, z = 0, a = 0;
                    foreach (XmlAttribute at in n.Attributes)
                    {
                        switch (at.Name)
                        {
                            case "x":
                                x = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "y":
                                y = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "z":
                                z = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "a":
                                a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                        }
                    }
                    distance = new PR3(x, y, z);
                }

                if (n.Name == "Angle")
                {

                    double a = 0;
                    foreach (XmlAttribute at in n.Attributes)
                    {
                        switch (at.Name)
                        {
                            case "a":
                                a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                        }
                    }
                    angle = a;
                }

                foreach (XmlAttribute a in node.Attributes)
                {
                    if (node.Name == "Light")
                    {
                        if (a.Name == "type")
                        {
                            if (a.Value == "spotlight")
                            {
                                light = new Graphics.Lights.SpotLight(distance,new VR3(direction),angle);
                            }
                        }
                    }
                }

            }

            return light;
        }

        public Graphics.Camera ReadCameraNode(XmlNode node)
        {
            Graphics.Camera camera = null;
            PR3 direction = null;
            PR3 distance = null;
            PR3 up = null;
            double focal = 0;

            foreach (XmlNode n in node.ChildNodes)
            {
                if (n.Name == "Direction")
                {

                    double x = 0, y = 0, z = 0, a = 0;
                    foreach (XmlAttribute at in n.Attributes)
                    {
                        switch (at.Name)
                        {
                            case "x":
                                x = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "y":
                                y = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "z":
                                z = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "a":
                                a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                        }
                    }
                    direction = new PR3(x, y, z);
                }
                if (n.Name == "Position")
                {

                    double x = 0, y = 0, z = 0, a = 0;
                    foreach (XmlAttribute at in n.Attributes)
                    {
                        switch (at.Name)
                        {
                            case "x":
                                x = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "y":
                                y = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "z":
                                z = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "a":
                                a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                        }
                    }
                    distance = new PR3(x, y, z);
                }
                if (n.Name == "Up")
                {

                    double x = 0, y = 0, z = 0, a = 0;
                    foreach (XmlAttribute at in n.Attributes)
                    {
                        switch (at.Name)
                        {
                            case "x":
                                x = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "y":
                                y = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "z":
                                z = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                            case "a":
                                a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                        }
                    }
                    up = new PR3(x, y, z);
                }


                if (n.Name == "Focal")
                {

                    double a = 0;
                    foreach (XmlAttribute at in n.Attributes)
                    {
                        switch (at.Name)
                        {
                            case "a":
                                a = double.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                                break;
                        }
                    }
                    focal = a;
                }


            }
            if (node.Name == "Camera")
            {

                camera = new Camera(distance, direction, new VR3(up), focal);

            }

            return camera;
        }

        public Graphics.Film ReadFilmNode(XmlNode node)
        {
            
            Graphics.Film film = null;
            int x = 100;
            int y = 100;


            foreach (XmlAttribute at in node.Attributes)
            {
                switch (at.Name)
                {
                    case "x":
                        x = int.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                        break;
                    case "y":
                        y = int.Parse(at.Value, System.Globalization.CultureInfo.InvariantCulture);
                        break;
                }
            }

            if (node.Name == "Film")
            {
                film = new FilmColorAna(Film.TYPE.T24x36, x, y);
            }


            return film;
        }
    }
}
